require 'rubygems'
require 'xml/libxml'
require 'rexml/document'
require 'family_tree_api/summary_person/event'

module FamilyTreeApi
  module SummaryPerson
    NS = ['fs:http://api.familysearch.org/familytree/v1','fsapi:http://api.familysearch.org/v1']
    class Base
      attr_accessor :id, :name, :gender, :birth, :death, :marriage, :father_id, 
                    :mother_id, :father, :mother, :spouse_ids, :spouses,
                    :children_ids, :children
      @xml_ns = { 'z' => 'http://api.familysearch.org/familytree/v1'}
      
      def initialize
        @spouse_ids = []
        @spouses = []
        @children_ids = []
        @children = []
      end
      
      def parse(p_element)
        @id = p_element.attributes['id']
        summary_element = p_element.children.first
        events = []
        summary_element.each do |e|
          case e.name
          when 'name'
            @name = SummaryPerson::Name.parse(e)
          when 'gender'
            @gender = e.content
          when 'events'
            events = e.collect do |ev|
              FamilyTreeApi::SummaryPerson::Event.parse(ev) if ev.name == 'event'
            end
          when 'parents'
            parse_parent_ids(e)
          when 'spouses'
            parse_spouse_ids(e)
          when 'children'
            parse_children_ids(e)
          end
        end
        # parse_parent_ids p_element
        # parse_spouse_ids p_element
        # parse_children_ids p_element
        @birth = events.select{ |e| e.type == 'Birth' }.first
        @death = events.select{ |e| e.type == 'Death' }.first
        @marriage = events.select{ |e| e.type == 'Marriage' }.first
      end
      
      def self.parse(xml_str, ancestors = 0, descendants = 0)
        xp = XML::Parser.new
        xp.string = xml_str
        doc = xp.parse.root
        people = doc.find("/fs:familytree/fs:persons/fs:person",NS).collect do |p_element|
          person = self.new
          person.parse p_element
          person
        end
        if ancestors > 0
          link_ancestors(people)
        end
        if descendants > 0
          link_descendants(people)
        end
        people.first
      end
      
      private
      def parse_parent_ids parents_element
        parents = parents_element.collect do |p|
          {
            :role => p.attributes['role'],
            :ref => p.attributes['ref']
          }
        end
        father = parents.select { |p| p[:role] == 'Father' }.first
        mother = parents.select { |p| p[:role] == 'Mother' }.first
        @father_id = father[:ref] if father
        @mother_id = mother[:ref] if mother
      end
      
      def parse_spouse_ids spouses_element
        @spouse_ids = spouses_element.collect do |p|
          p.attributes['ref']
        end
      end
      
      def parse_children_ids children_element
        @children_ids = children_element.collect do |p|
          p.attributes['ref']
        end
      end
      
      def self.link_ancestors(people)
        person_index = create_index people
        people.each do |p|
           p.father = person_index[p.father_id] if p.father_id && person_index[p.father_id]
           p.mother = person_index[p.mother_id] if p.mother_id && person_index[p.mother_id]
        end
      end
      
      def self.link_descendants(people)
        person_index = create_index people
        people.each do |p|
          p.spouses = p.spouse_ids.select { |s_id| 
            !person_index[s_id].nil?  
          }.collect { |s_id| person_index[s_id] }
           
          p.children = p.children_ids.select { |ch_id| 
            !person_index[ch_id].nil? 
          }.collect { |ch_id| person_index[ch_id] if person_index[ch_id]}
        end
      end
      
      def self.create_index(people)
        index = {}
        people.each { |p| index[p.id] = p }
        index
      end
    end
    
    class Name
      attr_accessor :full_text, :given, :family
      
      def parse(n_element)
        n_element.each do |f|
          f.each do |e|
            case e.name
            when 'fullText'
              @full_text = e.content
            end
          end
        end
        name_pieces = n_element.find("fs:form/fs:pieces/fs:piece",NS) 
        @given = parse_given_name(name_pieces) if name_pieces
        @family = parse_family_name(name_pieces) if name_pieces
      end
      
      def self.parse(n_element)
        name = self.new
        name.parse n_element
        name
      end
      
      private
      def parse_given_name(name_pieces)
        given_name_array = name_pieces.select { |e| 
          e.attributes["type"]=="Given" 
        }.collect { |e| 
          e.find_first("fs:value",NS).content 
        }
        name = given_name_array.join(" ") || ""
      end
      
      def parse_family_name(name_pieces)
        family_name_array = name_pieces.select { |e| 
          e.attributes["type"]=="Family" 
        }.collect { |e| 
          e.find_first("fs:value",NS).content 
        }
        name = family_name_array.join(" ") || ""
      end
    end
  end
end